﻿using Centny.PdfReader.IO;
using Centny.PdfReader.Types;
using Centny.PdfReader.util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Centny.PdfReader.Operator.Text
{
    //Tz
    public class SetHorizontalScaling : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tz"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.SetHorScaling(op.Args[0] as PdfDouble);
        }
    }
    //TJ
    public class ShowTextGlyph : PdfOperatorExecuter
    {

        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "TJ"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            double hscaling = this.Lexer.GraphicsState.TextState.HorizontalScaling / 100.0;
            PdfArray ary = op.Args[0] as PdfArray;
            foreach (PdfClass cls in ary.Objects)
            {
                if (cls is PdfDouble)
                {
                    double adjustment = (cls as PdfDouble).Val;
                    adjustment = -(adjustment / 1000) * hscaling * this.Lexer.GraphicsState.TextState.Font.FontSize;
                    PdfMatrix m = new PdfMatrix();
                    m.Set(2, 0, adjustment);
                    m.Multiply(this.Lexer.GraphicsState.TextState.TextMatrix, this.Lexer.GraphicsState.TextState.TextMatrix);
                }
                else if (cls is PdfString)
                {
                    this.Lexer.OnDraw(cls as PdfString);
                }
                else
                {
                    throw new InvalidOperationException("unknowed argument for TJ");
                }
            }
        }
    }
    //Tj
    public class ShowText : PdfOperatorExecuter
    {

        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tj"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.OnDraw(op.Args[0] as PdfString);
        }
    }
    //Tf
    public class SetFont : PdfOperatorExecuter
    {

        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tf"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.SetFontNameSize(op.Args[0] as PdfName, op.Args[1] as PdfDouble);
        }
    }
    //Td.
    public class MovePosition : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Td"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            PdfMatrix m = new PdfMatrix();
            m[2][0] = (op.Args[0] as PdfDouble).Val;
            m[2][1] = (op.Args[1] as PdfDouble).Val;
            m.Multiply(this.Lexer.GraphicsState.TextState.LineMatrix, this.Lexer.GraphicsState.TextState.LineMatrix);
            this.Lexer.GraphicsState.TextState.TextMatrix = this.Lexer.GraphicsState.TextState.LineMatrix.Clone();
            //this.Lexer.TextCtm=m.Mulp(this.Lexer.TextCtm);
        }
    }
    //BT
    public class BegText : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "BT"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.OnBegText();
        }
    }
    //ET
    public class EndText : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "ET"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.OnEndText();
        }
    }
    //Tm
    public class SetMatrix : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tm"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            PdfMatrix m = new PdfMatrix();
            if (op.Args.Count < 6)
            {
                throw new InvalidOperationException("invalid cm opertaor arguments");
            }

            m[0][0] = (op.Args[0] as PdfDouble).Val;
            m[0][1] = (op.Args[1] as PdfDouble).Val;
            m[1][0] = (op.Args[2] as PdfDouble).Val;
            m[1][1] = (op.Args[3] as PdfDouble).Val;
            m[2][0] = (op.Args[4] as PdfDouble).Val;
            m[2][1] = (op.Args[5] as PdfDouble).Val;
            this.Lexer.GraphicsState.TextState.TextMatrix = m;
            this.Lexer.GraphicsState.TextState.LineMatrix = m.Clone();
        }
    }
    //Tw
    public class SetWordSpacing : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tw"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.GraphicsState.TextState.WordSpacing = (op.Args[0] as PdfDouble).Val;
        }
    }
    //Tc
    public class SetCharSpacing : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "Tc"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            if (op.Args.Count > 0)
            {
                PdfClass cls = op.Args[0];
                if (cls is PdfDouble)
                {
                    this.Lexer.GraphicsState.TextState.CharacterSpacing = (cls as PdfDouble).Val;
                }
            }
        }
    }
    //TL
    public class SetTextLeading : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "TL"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            this.Lexer.GraphicsState.TextState.Leading = (op.Args[0] as PdfDouble).Val;
        }
    }
    //T*
    public class NextLine : PdfOperatorExecuter
    {
        public PdfStreamLexer Lexer
        {
            get;
            set;
        }

        public string Operator
        {
            get { return "T*"; }
        }

        public void Execute(Types.PdfOperator op)
        {
            PdfOperator nop = new PdfOperator("Td");
            nop.Args.Add(new PdfDouble(0.0f));
            nop.Args.Add(new PdfDouble(-1 * this.Lexer.GraphicsState.TextState.Leading));
            this.Lexer.Process(nop);
        }
    }
}
